﻿/**
 * 
 * Copyright 2009, 2010 Mike Jamer [email: mikejamer@gmail.com ]
 * 
 * This File is part of Moose IRC
 * 
 * MooseIRC is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * MooseIRC is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with MooseIRC.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace mooseirc.controls
{
    /// <summary>
    /// Handles Rendering of Server Responses,
    /// and of course user interaction...
    /// </summary>
    /// <remarks>
    /// Need to be able to scroll up and down
    /// also need to be able to select and copy text
    /// 
    /// Once thats done, need to be able to add colors,
    /// and need to be more aware of what we're hovering over,
    /// so we can have relevant context menus, or clicks/double 
    /// clicks and the like...
    /// 
    /// 
    /// </remarks>
    public partial class OututputControl : UserControl
    {

        #region [Local Attributes]

        /// <summary>
        /// Content
        /// </summary>
        private List<string> m_content;

        /// <summary>
        /// maximum lines to show
        /// </summary>
        private int m_max_lines_show;

        /// <summary>
        /// Current Mouse Position
        /// </summary>
        private Point m_mouse_position;

        #endregion

        #region [Construction]

        /// <summary>
        /// Initialize Output Control
        /// </summary>
        public OututputControl()
        {
            InitializeComponent();
            m_content = new List<string>();
            DoubleBuffered = true;
            this.SetStyle(ControlStyles.AllPaintingInWmPaint
                | ControlStyles.UserPaint
                | ControlStyles.OptimizedDoubleBuffer, true);
            return;
        }

        #endregion

        #region [Public Methods]

        /// <summary>
        /// Write to the output window
        /// </summary>
        /// <param name="message"></param>
        public void write(string message)
        {
            m_content.Add (message);

            update_scroll_maximum();

            scroll_bar.Value = scroll_bar.Maximum;
            Invalidate();
            return;
        }

        #endregion

        #region [Helper Methods]

        /// <summary>
        /// Updates the maximum for scroller
        /// </summary>
        private void update_scroll_maximum()
        {

            if (m_content.Count >= m_max_lines_show)
                scroll_bar.Maximum = (m_content.Count - m_max_lines_show) + 1;
            else
                scroll_bar.Maximum = 0;

            return;
        }

        #endregion

        #region [Overrides]

        /// <summary>
        /// Override Windows Message Processing
        /// </summary>
        /// <param name="m">Windows Message</param>
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case Win32.WM_ERASEBKGND:
                    break; 
                default:
                    base.WndProc(ref m);
                    break;
            };
            return;
        }

        /// <summary>
        /// Custom Paint Process
        /// </summary>
        protected override void OnPaint(PaintEventArgs e)
        {
            int x = 2,
                y = 0;

            update_scroll_maximum();

            using (Bitmap graphics_buffer = new Bitmap(this.Width, this.Height, e.Graphics))
            {
                using (Graphics g = Graphics.FromImage(graphics_buffer))
                {
                    g.Clear(BackColor);
                    g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
                    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                    
                    

                    for (int i = scroll_bar.Value; i < m_content.Count; i++) //not drawing correctly once the box is full
                    {
                        g.DrawString(m_content[i],
                            this.Font,
                            new SolidBrush(this.ForeColor),
                            x, y, StringFormat.GenericTypographic);
                        y += Font.Height + 2;
                    }

                    if (m_content.Count < m_max_lines_show)
                        e.Graphics.DrawImageUnscaled(
                            graphics_buffer, 0,
                            Height - ((m_content.Count * (Font.Height + 2))));

                    else
                        e.Graphics.DrawImageUnscaled(
                            graphics_buffer, 0, 0);

                }
            }
            { //Drawing the cross where the mouse is for debugging purposes, this wont be here for long, worry not...
                e.Graphics.DrawLine(Pens.Blue,
                    new Point(m_mouse_position.X - 5, m_mouse_position.Y),
                    new Point(m_mouse_position.X + 5, m_mouse_position.Y));
                e.Graphics.DrawLine(Pens.Blue,
                    new Point(m_mouse_position.X , m_mouse_position.Y - 5),
                    new Point(m_mouse_position.X , m_mouse_position.Y + 5));
            }

            base.OnPaint(e);
            return;
        }

        /// <summary>
        /// Fires on Resize
        /// </summary>
        /// <param name="e">Event Args</param>
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            m_max_lines_show = Height / (Font.Height + 2) + 1;
            Invalidate();
            return;
        }

        /// <summary>
        /// Fires on font change
        /// </summary>
        /// <param name="e">Event Args</param>
        protected override void OnFontChanged(EventArgs e)
        {
            base.OnFontChanged(e);
            m_max_lines_show = Height / (Font.Height + 2) + 1;
            Invalidate();
            return;
        }

        //TODO: Implement scrolling capability with the mouse wheel

        /// <summary>
        /// Fired when mouse enters control
        /// </summary>
        /// <param name="e">Mouse Event Args</param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            m_mouse_position = e.Location;
            //TODO: if we are presently selecting text, then move the selection around

            Invalidate();

            base.OnMouseMove(e);
        }

        /// <summary>
        /// Fires when mouse button is down
        /// </summary>
        /// <param name="e">Mouse Event Args</param>
        protected override void OnMouseDown(MouseEventArgs e)
        {

            //TODO: Allow selection to be made

            base.OnMouseDown(e);
        }

        /// <summary>
        /// Fires when mouse button is up
        /// </summary>
        /// <param name="e">Mouse Event Args</param>
        protected override void OnMouseUp(MouseEventArgs e)
        {

            //TODO: copy whatever text has been selected to the clipboard

            base.OnMouseUp(e);
        }

        /// <summary>
        /// Fires whne mouse is clicked
        /// </summary>
        /// <param name="e">Mouse Event Args</param>
        protected override void OnMouseClick(MouseEventArgs e)
        {
            /**
             * Not sure what I'm going to do with the output control, I dont really want the
             * control to be selectable
             */

            base.OnMouseClick(e);
        }

        #endregion

        #region [Event Handlers]

        /// <summary>
        /// Fires when scroll bar scrolls
        /// </summary>
        private void scroll_bar_Scroll(object sender, ScrollEventArgs e)
        {
            Invalidate(); //Paint will take care of the rest...
            return;
        }

        #endregion

    }
}
